package alejandro.castro.bolita;

import java.awt.Graphics2D;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import alejandro.castro.arkanoid.ArkanoidScene;
import alejandro.castro.extras.BloqueComponent;
import alejandro.castro.extras.Point;
import alejandro.castro.ladrillo.Ladrillo;
import alejandro.castro.paleta.Paleta;
import alejandro.castro.visual.BolitaAppearance;

import com.uqbar.vainilla.DeltaState;
import com.uqbar.vainilla.GameComponent;
import com.uqbar.vainilla.colissions.CollisionDetector;


public class Bolita extends GameComponent<ArkanoidScene> {
	private int diameter;
	private int ratio = 15;
	private double speed = 300;
	private double xMove, yMove, backUpx, backUpy;
	
	private transient double advanced;
	private boolean cambiePosicion;
	
	private transient List<Ladrillo> ladrillosParaBorrar = new LinkedList<Ladrillo>();
	
	public Bolita() {
		this.diameter = ratio*2;
		this.setAppearance(new BolitaAppearance(diameter));
	}

	private void initialize() {
		cambiePosicion = false;
		Random random = new Random();
		this.setX(random.nextDouble() * (this.wDisplay() - diameter));
		this.setY(random.nextDouble() * (this.hDisplay() - diameter));		
		Point versor = new Point(getRandomBetweenZeroPoinFive(random), getRandomBetweenZeroPoinFive(random)).toVersor();
		this.xMove = versor.getX();
		this.yMove = versor.getY();
	}
	
	@Override
	public void onSceneActivated() {	
		initialize();
		super.onSceneActivated();
	}

	@Override
	public void update(DeltaState deltaState) {
		desplazarDelta(deltaState);
		chequearColisionesYCorregirPosicion();
		while(cambiePosicion){
			cambiePosicion=false;
			chequearColisionesYCorregirPosicion();
		}		
		super.update(deltaState);
	}

	private void chequearColisionesYCorregirPosicion() {
		this.corregirPosicionConEscena();
		this.corregirPosicionConPaletas();
		this.corregirPosicionConLadrillos();
	}
	
	private void corregirPosicionConLadrillos() {
		for(Ladrillo ladrillo: this.getScene().getLadrillos()){
			if(this.colisionaConPaleta(ladrillo)){
				ladrillo.corregirPosicionBolita(this);
				ladrillosParaBorrar.add(ladrillo);
			}
		}
		this.borrarLadrillos();
	}

	private void borrarLadrillos() {
		for(Ladrillo ladrillo: this.ladrillosParaBorrar){			
			this.getScene().removerLadrillo(ladrillo);
		}		
	}

	public void move(double dx, double dy) {
		super.move(dx, dy);
		cambiePosicion = true;
	}

	private void desplazarDelta(DeltaState deltaState) {
		advanced = this.speed * deltaState.getDelta();
		this.move(this.xMove * advanced, this.yMove * advanced);
	}

	private void corregirPosicionConPaletas() {
		for(Paleta paleta: this.getScene().getPaletas()){
			if(this.colisionaConPaleta(paleta)){
				paleta.corregirPosicionBolita(this);
			}
		}
	}

	private boolean colisionaConPaleta(BloqueComponent paleta) {
		return CollisionDetector.INSTANCE.collidesCircleAgainstRect(this.getX(), this.getY(), this.ratio, paleta.getX(), paleta.getY(), paleta.getWidth(), paleta.getHeight());
	}
	
	private void corregirPosicionConEscena() {
		if(this.borderRight() > this.wDisplay()){
			invertirXMove();
			rebotarPorDerechaContra(this.wDisplay());
		}
		if(this.borderLeft() < 0){
			invertirXMove();
			rebotarPorIzquierdaContra(0);
		}		
		if(this.borderBottom() > this.hDisplay()){			
			stop();
			this.getScene().tocoBordeInferior(this);
			this.setY(this.hDisplay() - diameter);
		}
		if(this.borderTop() < 0){
			invertirYMove();
			rebotarPorArribaContra(0);
		}
	}
	
	public void rebotarPorDerechaContra(double lineaRebote){
		this.move((lineaRebote - this.borderRight())*2, 0);
	}
	
	public void rebotarPorIzquierdaContra(double lineaRebote){
		this.move((lineaRebote - this.borderLeft())*2, 0);
	}
	
	public void rebotarPorDebajoContra(double lineaRebote){
		this.move(0, (lineaRebote - this.borderBottom())*2);		
	}
	
    public void rebotarPorArribaContra(double lineaRebote){
    	this.move(0, (lineaRebote - this.borderTop())*2);
	}

	public void invertirYMove() {
		yMove = -yMove;
	}

	public void invertirXMove() {
		xMove = -xMove;
	}


	public void stop() {
		backUpMove();		
		yMove = 0;
		xMove = 0;
	}

	private void backUpMove() {
		backUpy = yMove;
		backUpx = xMove;
	}
	
	public void play() {	
		yMove = backUpy;
		xMove = backUpx;		
	}
	


	
	@Override
	public void render(Graphics2D graphics) {
		super.render(graphics);
	}
	
	private double getRandomBetweenZeroPoinFive(Random random){
		double res = 0.0;
		while(res == 0.0){
			res = random.nextDouble() - 0.5;
		}
		return res;
	}
	
	public double borderLeft(){
		return this.getX();
	}	
	public double borderRight(){
		return this.getX() + diameter;
	}	
	public double borderTop(){
		return this.getY();
	}	
	public double borderBottom(){
		return this.getY() + diameter;
	}
	public double centerY(){
		return this.getY() + ratio;
	}
	public double centerX(){
		return this.getX() + ratio;
	}
	
 	private int wDisplay(){
		return this.getGame().getDisplayWidth();
	}	
	private int hDisplay(){
		return this.getGame().getDisplayHeight();
	}

	public void sumarVector(Point point) {
		point.addX(xMove);
		point.addY(yMove);
		point.toVersor();
		this.xMove = point.getX();
		this.yMove = point.getY();		
	}

	public boolean mueveHaciaArriba() {
		return (yMove > 0);
	}

	public boolean mueveHaciaDerecha() {
		return (xMove > 0);
	}
	


}
